The scope of names (variables) are maintained by Namespaces, which are dictionaries containing the names of the objects (references) and the objects themselves.
As we have seen that names are not pre-defined thus Python uses the code block of the assignment of a name to associate it with a particular namespace. In other words, the place where you assign a name in your source code determines its scope of visibility.
Python uses lexical
scoping, which means that variable scopes are determined entirely by their locations in the source code and not by function calls.
Rules for names inside Functions are as follows
def
can only be seen by the code within that def
and cannot be referred from outside the function.def
do'nt clash with variables from outside the def
. i.e. a name assigned outside a def
is a completely different variable from a name assigned inside that def
.defs
, then it is global to the entire file and can be accessed with the help of global
keyword inside the def
.Normally, the names are defined in two dictionaries, which can be accessed through the functions locals()
and globals()
. These dictionaries are updated dynamically at runtime.
Global variables can be overshadowed by local variables (because the local scope is consulted before the global scope). To avoid this, you must declare the variable as global in the local scope.
example:
In [2]:
a = 10
def test():
print(a)
a = 12
test()
print(a)
In [1]:
a = 10
def test():
a = 12
print(a)
test()
print(a)
In [2]:
a = 10
def test():
"""
- Only for viewing value of Global Variable
- Cannot change the global variable
"""
print(a)
test()
print(a)
In [5]:
a = 10
def test():
"""
- When you need to update the value of Global variable
"""
global a
print(a)
a = 12
print(a)
print(id(a))
# print(locals())
# print(globals())
print(a)
test()
print(id(a))
print(a)
In [12]:
In [9]:
def test():
"""
Updating the data
"""
global glb
print(glb)
glb = 12
test()
glb = 10
print(glb)
In [11]:
def test():
"""
Updating the data
"""
global glb
print(glb)
glb = 12
glb = 10
test()
print(glb)
In [12]:
def test():
"""
Updating the data
"""
global glb1
glb1 = 12
print(glb1)
test()
print(glb)
In [14]:
a = 10
def test():
global a
a = "Chennai Riders"
print(a)
a = "Pune Rocks"
test()
print(a)
In [1]:
global a
a = 10
def test():
a = "Pune Rocks"
print(a)
print(locals())
print("~"*20)
# print(globals())
test()
print(a)
In [7]:
a = 10
def test(a):
print(a)
a = "Pune Rocks"
print(locals())
return a
a= test(a)
print(a)
print(len(locals()))
print(len(globals()))
In [17]:
def addlist(lists):
"""
Add lists of lists, recursively
the result is global
"""
global add
for item in lists:
if isinstance(item, list): # If item type is list
addlist(item)
else:
add += item # add = add + item
add = 0
addlist([[1, 2], [3, 4, 5], 6])
print(add)
In [5]:
# add = 10
def addlist(lists):
"""
Add lists of lists, recursively
the result is global
"""
global add2
for item in lists:
if isinstance(item, list): # If item type is list
addlist(item)
else:
if 'add2' in globals():
add2 += item
else:
print("Creating add")
add2 = item
addlist([[1, 2], [3, 4, 5], 6])
print(add2)
Using global variables is not considered a good development practice, as they make the system harder to understand, so it is better to avoid their use. The same applies to overshadowing variables.
In [3]:
#add = 10
def addlist(lists):
"""
Add lists of lists, recursively
the result is global
"""
global add
for item in lists:
if isinstance(item, list): # If item type is list
addlist(item)
x = 100
else:
add += item
print(x)
addlist([[1, 2], [3, 4, 5], 6])
print(add)
In [4]:
def outer():
a = 0
b = 1
def inner():
print(a)
print(b)
inner()
outer()
NOTE: - A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects.
In [19]:
def outer():
a = 0
b = 1
def inner():
print(a)
print(b)
b = 4
inner()
outer()
In [23]:
def outer():
a = 0
print("outer: ", a)
def inner():
global a
print("inner: ", a)
inner()
a = 200
b = 10
outer()
print("base")
print(a)
print(b)
In [25]:
def List_fun(l, a=[]):
"""function takes 2 parameters list having values and empty list."""
for i in l:
#checking whether the values are list or not
if isinstance(i, list):
List_fun(i, a)
else:
a.append(i)
return a
b=[]
l2 = List_fun([[1,2],[3,[4,5]],6,7], b)
print(l2)
print(b)
print(id(l2))
print(id(b))
In [21]:
def List_fun(l, a=[]):
"""function takes 2 parameters list having values and empty list."""
for i in l:
#checking whether the values are list or not
if isinstance(i, list):
List_fun(i, a)
else:
a.append(i)
b=[]
List_fun([[1,2],[3,[4,5]],6,7], b)
print(b)
In [28]:
def fun_numbers(a):
print(a)
print(id(a))
a += 10
print(a)
print(id(a))
b = 10
print(id(b))
fun_numbers(b)
print(b)
In [32]:
def fun_numbers(a):
print(a)
print(id(a))
a = [20]
print(a)
print(id(a))
b = [10]
print(id(b))
fun_numbers(b)
print(b)
In [33]:
def fun_numbers(a):
print(a)
print(id(a))
a.append(20)
print(a)
print(id(a))
b = [10]
print(id(b))
fun_numbers(b)
print(b)
In [34]:
def fun_numbers(a):
print(a)
a.append(120)
print(a)
b = [10]
fun_numbers(b)
print(b)
In [35]:
def func():
a = 10
for d in [10,20,30]:
a = a+d
print(a)
func()